/********************************************************
 * Filename: NewTclProject.java
 * Author: LMU
 * Program: TUnit
 * Description: Creates the tcl project from File -> New 
 * -> Project -> Tcl Project menu selection.      
 * Revision History:
 * 20060421: Initial Revision.
 * 20061008: Did a little refactoring.  
 * *****************************************************/

package edu.lmu.cs.tUnit.wizard;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.dialogs.WizardNewProjectCreationPage;

import edu.lmu.cs.tUnit.log.TUnitLog;
import edu.lmu.cs.tUnit.plugin.TUnitPlugin;

/**
 * Class to create a new tcl project
 * @author LMU
 */
public class NewTclProject extends Wizard implements INewWizard {
	
	// Pages to be used
	private WizardNewProjectCreationPage projectNameAndLocation;
	
	// workbench in use
	private IWorkbench workbench;
	
	/**
	 * Constructor for NewTclProject.
	 */
	public NewTclProject() {
		super();
		setWindowTitle("New Tcl Project");
		setNeedsProgressMonitor(true);
	}
	
	/**
	 * Adding the page to the wizard.
	 */
	public void addPages() {
		projectNameAndLocation = new WizardNewProjectCreationPage("New Tcl Project");
		projectNameAndLocation.setDescription("This wizard creates a new Tcl Project to be used in the Tcl Perspective.");
		projectNameAndLocation.setTitle("New Tcl Project");
		addPage(projectNameAndLocation);
	}

	/**
	* This method is called when 'Finish' button is pressed in
	* the wizard. We will create an operation and run it
	* using wizard as execution context.
	*/
	public boolean performFinish() {
		WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
			protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException {
				finishPage(monitor);
			}
		};
		
		try {
			getContainer().run(false, true, op);
		} catch (InvocationTargetException e) {
			return false; 
		} catch  (InterruptedException e) {
			return false; // canceled
		}
		return true;
	}

	/**
	 * Finish up by creating the project and opening the perspective
	 * @param monitor
	 * @throws InterruptedException
	 * @throws CoreException
	 * @throws IOException 
	 */
	private void finishPage(IProgressMonitor monitor) throws InterruptedException, CoreException {
		Calendar cal = Calendar.getInstance();
		Date today = cal.getTime();
		SimpleDateFormat dateFormat =new SimpleDateFormat("MM-dd-yyyy");
		String todayString = dateFormat.format(today);
		
		if (monitor == null) {
			monitor = new NullProgressMonitor();
		}
		try {		
			String strName = projectNameAndLocation.getProjectName();
			monitor.beginTask("Creating "+ strName + " Tcl Project", 3);

			IProject project = projectNameAndLocation.getProjectHandle();
			IPath locationPath = projectNameAndLocation.getLocationPath();
			
			// create the project
			IProjectDescription description = ResourcesPlugin.getWorkspace().newProjectDescription(projectNameAndLocation.getProjectName());
			if (!projectNameAndLocation.useDefaults()) {
				description.setLocation(locationPath);
			}

			project.create(description, new SubProgressMonitor(monitor, 1));
			project.open(new SubProgressMonitor(monitor, 1));
			
			// Switch to the Tcl perspective
			monitor.subTask("Switching to the Tcl Perspective");
			workbench.showPerspective("edu.lmu.cs.tUnit.perspective.tcl", workbench.getActiveWorkbenchWindow());
			
			// Create tcl files
			FileOutputStream global;
			File init;
			try {
				if(projectNameAndLocation.useDefaults()) { 
					global = new FileOutputStream(locationPath.toString()+ "/" + projectNameAndLocation.getProjectName() + "/global.tcl");
					init = new File(locationPath.toString()+ "/" + projectNameAndLocation.getProjectName() + "/init.tcl");
				}
				else {
					global = new FileOutputStream(locationPath.toString() + "/global.tcl");
					init = new File(locationPath.toString() + "/init.tcl");
				}
			} catch (FileNotFoundException e) {
				TUnitLog.logError("Could not find output file.", e);
				return;
			}
			
			try {
				File targetLocation;
				String topLevel;
				if(projectNameAndLocation.useDefaults()) {
					copyFile("/resource/sampleInit.tcl", init);
					targetLocation = new File(locationPath.toString()+ "/" + projectNameAndLocation.getProjectName() + "/t-unit");
					topLevel = locationPath.toString()+ "/" + projectNameAndLocation.getProjectName();
				}
				
				else {
					copyFile("/resource/sampleInit.tcl", init);
					targetLocation = new File(locationPath.toString() + "/t-unit");
					topLevel = locationPath.toString();
				}
				
				copyTUnit(topLevel, targetLocation);
				processSampleFile(init, todayString);
			} catch (IOException e){
				TUnitLog.logError("Could not create the files for the " + projectNameAndLocation.getProjectName() + " project.", e);
			}
			createGlobalFile(todayString, global);
			
			project.refreshLocal(IProject.DEPTH_INFINITE, monitor);
			monitor.worked(3);
			
		} finally {
			monitor.done();
			TUnitLog.logInfo("New Tcl Project " + projectNameAndLocation.getProjectName() + " created.");
		}
	}

	/**
	 * Creates the global.tcl file
	 * @param todayString today's date
	 * @param global the file to be created
	 */
	private void createGlobalFile(String todayString, FileOutputStream global) {
		PrintStream pOut;
		pOut = new PrintStream(global);
		pOut.println("# This file was generated by the Tcl Project on " + todayString + ".");
		pOut.println("# Add any global variable declarations to this file.");
		pOut.println("# Also add any additional setup and teardown for each testcase.\n");
		pOut.println("proc setup {} {\n");
		pOut.println("}\n");
		pOut.println("proc teardown {} {\n");
		pOut.println("}\n");
		pOut.close();
	}
	
	/**
	 * Copy template file to output file
	 * @param inputFile
	 * @param fileOut
	 * @throws IOException
	 */
	private static void copyFile(String inputFile, File outputFile) throws IOException {
		URL SAMPLE = TUnitPlugin.getDefault().getBundle().getEntry(inputFile);
		InputStream in = SAMPLE.openStream();
		OutputStream out = new FileOutputStream(outputFile);
	    
        // Transfer bytes from in to out
        byte[] buf = new byte[1024];
        int len;
        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
        in.close();
        out.close();
    }
	
	/**
	 * Make changes to the template file.
	 * @throws IOException 
	 */
	private void processSampleFile(File file, String dateString) throws IOException {
		String fileBuffer = openFile(file);
		
		Pattern p = Pattern.compile("sampleDate");
		Matcher m = p.matcher(fileBuffer);
		fileBuffer = m.replaceAll(dateString);	
			
		writeFile(fileBuffer, file);
	}
	
	/**
     * Opens a file and imports it.
	 * @throws IOException 
	 * @throws FileNotFoundException 
     */
	private String openFile(File file) throws FileNotFoundException, IOException {	
		StringBuffer buffer = new StringBuffer();
		
		BufferedReader in = new BufferedReader(
				new FileReader(file.getCanonicalPath()));
		String line;
		while ((line = in.readLine()) != null) {
			buffer.append(line).append("\n");
		}
		in.close();
		return buffer.toString();
	}
	
	/**
     * Creates a new output file and saves the changes to it.
	 * @throws IOException 
     */
	private void writeFile(String fileBuffer, File ouputFile) throws IOException {
		BufferedWriter out = new BufferedWriter(new FileWriter(ouputFile));
		out.write(fileBuffer);
		out.close();
	}
	
	/**
	 * Copy t-unit to the project
	 */
	private void copyTUnit(String projectPath, File targetLocation) throws IOException {
		if (!targetLocation.exists()) {
			targetLocation.mkdir();
		}
		
		copyFile("/resource/t-unit/assertEquals.tcl", new File(targetLocation.getPath() + "/assertEquals.tcl"));
		copyFile("/resource/t-unit/assertEqualsList.tcl", new File(targetLocation.getPath() + "/assertEqualsList.tcl"));
        copyFile("/resource/t-unit/assertEqualsArray.tcl", new File(targetLocation.getPath() + "/assertEqualsArray.tcl"));
		copyFile("/resource/t-unit/assertEqualsReal.tcl", new File(targetLocation.getPath() + "/assertEqualsReal.tcl"));
		copyFile("/resource/t-unit/assertFalse.tcl", new File(targetLocation.getPath() + "/assertFalse.tcl"));
		copyFile("/resource/t-unit/assertNotEquals.tcl", new File(targetLocation.getPath() + "/assertNotEquals.tcl"));
		copyFile("/resource/t-unit/assertTrue.tcl", new File(targetLocation.getPath() + "/assertTrue.tcl"));
		copyFile("/resource/t-unit/global.tcl", new File(targetLocation.getPath() + "/global.tcl"));
		copyFile("/resource/t-unit/t-unit.tcl", new File(targetLocation.getPath() + "/t-unit.tcl"));
		copyFile("/resource/t-unit/t-unitTestCase.tcl", new File(targetLocation.getPath() + "/t-unitTestCase.tcl"));
		copyFile("/resource/t-unit/t-unittestcases.test", new File(targetLocation.getPath() + "/t-unittestcases.test"));
		copyFile("/resource/t-unit/unitTestHarness.tcl", new File(targetLocation.getPath() + "/unitTestHarness.tcl"));
	}
	
	/**
	* We will accept the selection in the workbench to see if
	* we can initialize from it.
	* @see IWorkbenchWizard#init(IWorkbench, IStructuredSelection)
	*/
	public void init(IWorkbench workbench, IStructuredSelection selection) {
		this.workbench = workbench;
		setNeedsProgressMonitor(true);
	}
}
